package org.modelcc.io.java.processor;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.modelcc.Pattern;
import org.modelcc.io.java.JavaLanguageClass;
import org.modelcc.io.java.JavaModelProcessor;
import org.modelcc.io.java.JavaModelReader;
import org.modelcc.io.java.JavaLanguageMetadata;
import org.modelcc.io.java.Reflection;

/**
 * Process attribute inheritance
 */
public class AttributeInheritanceProcessor extends JavaModelProcessor<JavaLanguageMetadata>
{	
	public AttributeInheritanceProcessor (JavaModelReader reader)
	{
		super(reader);
	}
	
	@Override
	public void process(JavaLanguageMetadata metadata) 
	{
		Set<JavaLanguageClass> elements = metadata.getJavaElements();
		Map<JavaLanguageClass,Set<JavaLanguageClass>> subclasses = metadata.getJavaSubclasses();
		Map<JavaLanguageClass,Integer> priorities = metadata.prePriorities;
		Map<JavaLanguageClass,Set<JavaLanguageClass>> precedences = metadata.prePrecedences;
		
    	JavaLanguageClass source;
    	JavaLanguageClass target;
    	Iterator<JavaLanguageClass> it1 = elements.iterator();

    	while (it1.hasNext()) {
    		source = (JavaLanguageClass) it1.next();
    		if (!Reflection.hasAnnotation(source.getElementClass(),Pattern.class)) {
    			Iterator<JavaLanguageClass> ite;
    			if (subclasses.get(source) != null) {
    				ite = subclasses.get(source).iterator();
    				//log(Level.INFO,"Extending attributes from \""+source.getClassName()+"\":");
    				while (ite.hasNext()) {
    					target = (JavaLanguageClass) ite.next();
    					inheritAttributesClass(subclasses,source,target,priorities,precedences);
    				}
    			}
    		}
    	}		
    }
	
    /**
     * Inherits attributes from a source to a target element
     * @param subclasses the subclasses map
     * @param source the source element
     * @param target the target element
     * @param priorities the priorities map
     * @param precedences the precedence map
     */
    private void inheritAttributesClass (
    		Map<JavaLanguageClass,Set<JavaLanguageClass>> subclasses,
    		JavaLanguageClass source, JavaLanguageClass target,
    		Map<JavaLanguageClass,Integer> priorities, 
    		Map<JavaLanguageClass,Set<JavaLanguageClass>> precedences) 
    {
    	Iterator<JavaLanguageClass> ite;
    	JavaLanguageClass target2;

    	// Associativity
    	if (target.getAssociativity()==null && source.getAssociativity()!= null) {
    		target.setAssociativity(source.getAssociativity());
    	}
    	// Composition
    	if (target.getComposition()==null && source.getComposition()!= null) {
    		target.setComposition(source.getComposition());
    	}
    	// FreeOrder
    	if (target.isFreeOrder()==null && source.isFreeOrder()!= null) {
    		target.setFreeOrder(source.isFreeOrder());
    	}
    	// Separator
    	if (target.getSeparator()==null && source.getSeparator()!= null) {
    		target.setSeparator(source.getSeparator());
    	}
    	// Value
    	if (target.getValueField()==null && source.getValueField()!= null) {
    		target.setValueField(source.getValueField());
    	}
    	// Priority
    	if (priorities.get(target) == null && priorities.get(source) != null) {
    		priorities.put(target,priorities.get(source));
    	}
    	if (precedences.get(target) == null && precedences.get(source) != null) {
    		precedences.put(target,precedences.get(source));
    		if (precedences.get(target).contains(target))
    			precedences.remove(target);
    	}
    	// Evaluator
    	if (target.getEvaluator()==null && source.getEvaluator()!= null) {
    		target.setEvaluator(source.getEvaluator());
    	}

    	if (subclasses.get(target) != null) {
    		ite = subclasses.get(target).iterator();
    		while (ite.hasNext()) {
    			target2 = (JavaLanguageClass) ite.next();
    			inheritAttributesClass(subclasses,target,target2,priorities,precedences);
    		}
    	}

    }
	
}
